home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 November / macformat-018.iso / Utility Spectacular / Developer / QB->FB / QB Convert next >
Encoding:
Text File  |  1993-02-17  |  51.5 KB  |  1,605 lines  |  [TEXT/ZBAS]

  1. '
  2. ' QuickBASIC to FutureBASIC Conversion Program
  3. ' ------------------------------------------------------
  4. '
  5. ' This program consists of four files:
  6. '
  7. '   QB Convert.BAS      = source code of conversion program
  8. '   QB->FB.data         = the actual conversion data required to
  9. '                         successfully convert a keyword in QuickBASIC
  10. '                         to FutureBASIC syntax
  11. '   qbCLR.INCL          = an Include file containing functions that
  12. '                         mimic the majority of Clear Lake Research
  13. '                         calls that are not simple Toolbox translations.
  14. '   QB->FB Instructions = A read me file containing pointers and notes
  15. '                         concerning these files and the translation
  16. '                         process.
  17. '
  18. ' ------------------------------------------------------
  19. '
  20. ' WHAT THIS PROGRAM CAN DO:
  21. ' This conversion program will translate a QuickBASIC source code file
  22. ' saved in TEXT format into a source code TEXT file FutureBASIC can use.
  23. ' It will ocnvert approximately 80% of the QB keywords into FB syntax including
  24. ' a majority of CLR and Toolbox calls. It will also convert multi-line
  25. ' IF/THEN statements into FB's LONG IF structures, change multi-statements
  26. ' line containing colons into single lines. Additionaly, it will convert QB 
  27. ' subroutine labels to FB format and convert SUBs into LOCAL FNs.
  28. '
  29. ' It also attempts to mark every statement not converted with appropriate
  30. ' references to the Reference or Handbook manuals for help in fixing
  31. ' your source code.
  32. '
  33. ' ------------------------------------------------------
  34. '
  35. ' WHAT THIS PROGRAM CANNOT DO:
  36. '
  37. ' It cannot deduce your program structure. While every attempt has been 
  38. ' made to make it as robust as possible in converting parameters, finding
  39. ' labels, or changing SUBs to LOCAL FNs, your method of programming can
  40. ' cause subtle errors to creep into the translated program.
  41. '
  42. ' Additionally, it does not attempt to rewrite any file handling routines
  43. ' included in the source file. There are just too many variables to trust
  44. ' an accurate translation and re-writing them is best left to the programmer
  45. ' to ensure the results are what they expect.
  46. '
  47. ' ALWAYS WORK ON A TEXT COPY OF THE ORIGINAL. 
  48. ' (See the Read Me file for more info on this)
  49. '
  50. ' If errors are present feel free to modify the source code to correct
  51. ' these deficiencies. The source code is provided AS IS with no guarantee
  52. ' of any results. The majority of routines have been documented to provide
  53. ' as much help as possible to make additions or changes relatively easy.
  54. ' Again, feel free to change or modify as necessary to best suit your
  55. ' purposes.
  56. '
  57. ' If you do modify the program, please provide as much documentation as
  58. ' as you can, and if distributing, be sure to include ALL the files mentioned
  59. ' above to keep the package complete for the next user.
  60. '
  61. '
  62. ' ------------------------------------------------------
  63. '
  64. _debug = 0
  65. COMPILE LONG IF _debug
  66.   TRON b
  67. COMPILE END IF
  68. '
  69. '----------------------- Constants ---------------------
  70.  
  71. COMPILE 0, _Macsbuglabels
  72.  
  73.  
  74. _maxKeywords        = 300
  75.  
  76. _qb                 = 0
  77. _fb                 = 1
  78.  
  79. _srcIndx            = 0
  80. _remIndx            = 1
  81. _hedIndx            = 2
  82. _labelIndx          = 3
  83. _ifIndx             = 4
  84.  
  85. _rem                = _"'"
  86. _space              = _" "
  87. _quote              = 34
  88. _comma              = _","
  89. _colon              = _":"
  90. _openP              = _"("
  91. _closeP             = _")"
  92. _bullett            = _"•"
  93. _caret              = _"^"
  94. _pound              = _"#"
  95. _att                = _"@"
  96. _asterisk           = _"*"
  97.  
  98.  
  99. _MaxFns  = 25
  100.  
  101.  
  102. '----------------------- Globals -----------------------
  103.  
  104. DIM 63 gFilename$                                        'name of output file
  105. DIM gTotalLines
  106. DIM buff.200
  107. DIM gExitSub
  108. DIM gHeaderLines
  109. DIM gTotalIFs
  110.  
  111. DIM 255 gStmnts$(20)
  112. DIM 63 gLabel$ (_maxKeywords)
  113. DIM 63 gSubs$  (_maxKeywords)
  114. DIM 63 gConv$  (_fb,_maxKeywords)                        '0 = QB keyword,  1 = FB equivalent
  115. DIM 99 gParam$ (9)                                       'array to hold parameters in statement
  116. DIM 99 gStmnt$ (9)                                       'array of actual line statements
  117.  
  118. DIM gProfile& (_MaxFNs)
  119.  
  120. END GLOBALS 
  121.  
  122. CLEAR 5000, _hedIndx
  123. CLEAR 1500, _ifIndx
  124. CLEAR 2000, _labelIndx
  125. CLEAR 5000, _remIndx
  126. CLEAR 5000, _srcIndx
  127.  
  128.  
  129. '----------------------- Functions ---------------------
  130.  
  131.  
  132.  
  133. LOCAL FN StartFN (FNID%)
  134.   gProfile& (FNID%) = gProfile& (FNID%) - FN TICKCOUNT
  135. END FN
  136.  
  137.  
  138.  
  139. LOCAL FN StopFN (FNID%)
  140.   gProfile& (FNID%) = gProfile& (FNID%) + FN TICKCOUNT
  141. END FN
  142.  
  143.  
  144.  
  145. LOCAL FN PrintFNCounts
  146.   CLS
  147.   FOR j = 1 TO _MaxFNs
  148.     IF gProfile& (j) <> 0 THEN PRINT j,gProfile& (j)
  149.   NEXT j
  150. END FN
  151.  
  152.  
  153. LOCAL FN doAlrt(s$)
  154.   CALL PARAMTEXT(s$,"","","")
  155.   item = FN STOPALERT(4,0)
  156. END FN = item
  157.  
  158.  
  159.  
  160.  
  161.  
  162. ' ------------------------------------------------------------------------
  163. ' this routine checks the free space in the specified INDEX$ and increases
  164. ' it if there isn't enough. It also tacks on a requested spare amount to
  165. ' reduce the number of times it must be changed.
  166. '
  167. ' size&        = number of bytes required free in INDEX$
  168. ' indxID       = ID of the INDEX$ to check
  169. ' spare&       = size of spare bytes to add in addition to size&
  170. '
  171. LOCAL FN CheckIndexSize (size&, indxID, spare&)          'is index large enough
  172.   indxSize& = MEM(indxID + _availBytes)                  'num bytes available in INDEX$
  173.   crntSize& = MEM(indxID + _maxBytes)                    'max bytes available to index$
  174.   LONG IF indxSize& < size&                              'less than requested size
  175.     CLEAR crntSize& + size& + spare&, indxID             'increase with size & spare
  176.     LONG IF MEM(indxID + _maxBytes) = crntSize&          'was INDEX$ resized?
  177.       BEEP : SYSERROR = _memFullErr                      'if no change we are out of memory
  178.     END IF
  179.   END IF
  180. END FN
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187. ' ------------------------------------------------------------------------
  188. ' this routine strips any designated character from the front of a string
  189. ' and replaces the original string with the modified one.
  190. '
  191. ' charPos      = the char position in the string
  192. ' strPtr&      = pointer to string to operate on
  193. ' newLen%      = length of new line after stripping
  194. '
  195. LOCAL FN stripLeadChar (@strPtr&, char, charPos)         'string addr and char to strip out
  196.   WHILE PEEK(strPtr& + charPos) = char                   'is this the char we are striping?
  197.     INC (charPos)                                        'yes, keep adding to count
  198.   WEND                                                   'until letter <> char
  199.   newLen% = PEEK(strPtr&) - charPos + 1                  'calc new length of string
  200.   BLOCKMOVE strPtr& + charPos, strPtr& + 1, newLen%      'blockmove end of string to front
  201.   POKE strPtr&, newLen%                                  'poke new length
  202. END FN                                                   'we are done!
  203.  
  204.  
  205.  
  206.  
  207.  
  208. ' ------------------------------------------------------------------------
  209. ' this routine strips any remarks from a line of source code and stores
  210. ' it in a second INDEX$. the two are re-combined when the file is output
  211. ' to disk.
  212. '
  213. ' source$       = source code line to strip remark from
  214. '
  215. LOCAL FN remarkBlaster$ (source$)                        'removes remarks from lines
  216.   remark$    = ""                                        'clear remark string
  217.   remarkPos  = INSTR(1, source$, "REM")                  'is there a REM in it?
  218.   apostrPos  = INSTR(1, source$, "'")                    'is there a apostrophe in it?
  219.   
  220.   LONG IF remarkPos <> 0 OR apostrPos <> 0               'if we got either
  221.     LONG IF remarkPos => apostrPos AND remarkPos <> 0
  222.       apostrPos = remarkPos                              'mark sure we get the first occurance
  223.     END IF
  224.     
  225.     remark$ = RIGHT$(source$, LEN (source$) - apostrPos)'strip remark from line
  226.     source$ = LEFT$(source$, apostrPos - 1)              'strip source code from line
  227.     
  228.     DEF TRUNCATE (source$)                               'delete any trailing spaces
  229.     DEF TRUNCATE (remark$)
  230.     FN stripLeadChar (remark$, _space, 1)                'strip leading spaces from line
  231.     
  232.     FN CheckIndexSize (LEN(remark$), _remIndx, 500)      'make room in remark INDEX$
  233.     LONG IF SYSERROR = _noErr                                     
  234.       INDEX$ (gTotalLines, _remIndx) = remark$           'place remark into its own INDEX$
  235.     END IF
  236.   END IF
  237. END FN = source$
  238.  
  239.  
  240.  
  241.  
  242. ' ------------------------------------------------------------------------
  243. ' this routine allows the user to select a TEXT file for conversion using
  244. ' a standard getfile dialog, then reads the source file into an INDEX$
  245. ' array for easier manipulation. as it reads the file in it disposes of 
  246. ' any leading space characters and strips all remarks from the line.
  247. ' additionally, the window name is changed to show which file is being
  248. ' converted.
  249. LOCAL
  250. DIM 255 source$
  251. LOCAL FN OpenFile                                        'open QB source code into Index$ array zero
  252.   gFilename$ = FILES$(_fOpen, "TEXT" ,,volRefNum%)
  253.   LONG IF LEN(gFilename$)
  254.     CURSOR _watchCursor
  255.     OPEN "I", 1, gFilename$, , volRefNum%                'open source code file
  256.     byte& = LOF(1,1)                                     'get file size
  257.     FN CheckIndexSize (byte&, _srcIndx, 5000)            '50K buffer
  258.     LONG IF SYSERROR = _noErr
  259.       filename$ = "Converting: " + gFilename$
  260.       WINDOW #1, filename$                               'show conversion name in window
  261.       CLS                                     
  262.       
  263.       gTotalLines = 0
  264.       DO
  265.         LONG IF (gTotalLines MOD 10) = 0
  266.           PRINT%(10,20) "Importing original source code…"
  267.           PRINT%(10,40) "Reading line #";gTotalLines
  268.         END IF
  269.         
  270.         LINE INPUT #1, source$                           'get next source code line
  271.         
  272.         FN stripLeadChar (source$, _space, 1)            'strip leading spaces from line
  273.         source$ = FN remarkBlaster$ (source$)            'strip remarks from line
  274.         
  275.         INDEX$(gTotalLines, _srcIndx) = source$          'put massaged source into INDEX$
  276.         INC(gTotalLines)
  277.       UNTIL EOF(1)
  278.       CLOSE #1
  279.     XELSE
  280.       item = FN doAlrt ("Not enough memory to convert this program!")
  281.       END
  282.     END IF
  283.   END IF
  284.   CALL INITCURSOR
  285. END FN
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293.  
  294. ' -----------------------------------------------------------------
  295. ' works like MID$ except that it can grow or shrink the string as
  296. ' required when inserting the replacement text
  297. '
  298. '
  299. LOCAL FN replaceSomething (@srcPtr&, charPos, @oldkeyPtr&, @newKeyPtr&)
  300.   strSize    = PEEK (srcPtr&)                            'get original size of source string
  301.   oldKeySz   = PEEK (oldkeyPtr&)                         'get old key size
  302.   newKeySz   = PEEK (newKeyPtr&)                         'get new key size
  303.   startPtr&  = srcPtr& + charPos + oldKeySz
  304.   endPosPtr& = startPtr& + (newKeySz - oldKeySz)
  305.   moveSize   = strSize - charPos + 1                     'calc num chars to move
  306.   newSize    = strSize + (newKeySz - oldKeySz)           'calc new string size
  307.   LONG IF newSize < 256                                  'still within max string length?
  308.     BLOCKMOVE startPtr&, endPosPtr&, moveSize
  309.     BLOCKMOVE newKeyPtr& + 1, srcPtr& + charPos, newKeySz'replace old key with new
  310.     POKE srcPtr&, newSize                                'set string to new size
  311.   XELSE
  312.     SYSERROR = _memSCErr                                 'size check failed error
  313.   END IF
  314. END FN
  315.  
  316.  
  317.  
  318.  
  319.  
  320.  
  321. ' ------------------------------------------------------------------------
  322. ' this routine sets up the program window and some default
  323. ' program and window attributes
  324. '
  325. LOCAL FN initialize
  326.   WIDTH _noTextWrap                                      'faster
  327.   gVolRefNum% = SYSTEM (_aplVol)                         'this is where I'll save the output file
  328.   WINDOW #1,"QB Convert", (0,0)-(400,200), _docNoGrow _NoGoAway
  329.   TEXT _monaco, 9, , 0
  330. END FN
  331.  
  332.  
  333.  
  334.  
  335.  
  336. ' ------------------------------------------------------------------------
  337. ' this routine converts a QB label to an FN label title format
  338. '
  339. ' label$        = label title being converted from QB->FB format
  340. '
  341. LOCAL FN quoteMe$ (label$)
  342.   label$ = CHR$(_quote) + label$ + CHR$(_quote)
  343. END FN = label$
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350. ' ------------------------------------------------------------------------
  351. ' this routine adds the components of a parsed string into separate
  352. ' lines in the source code. it also ensures that adequate memory is
  353. ' available to add the new lines and keeps remarks lined up with the
  354. ' original string location
  355. '
  356. ' lineNum      = line number in source code to add new lines
  357. ' statCount    = number of lines to add to source code
  358. '
  359. LOCAL FN insertFix (lineNum, statCount)                  'inserts parsed lines into program
  360.   LONG IF statCount > 0
  361.     INDEX$ D (lineNum, _srcIndx)                         'remove original
  362.     DEC(gTotalLines)                                     'decrement line count
  363.     
  364.     size = 0
  365.     FOR count = 0 TO statCount                           'how much memory do we need?
  366.       size = size + LEN(gStmnts$(count))                 'add each new line to total
  367.     NEXT
  368.     FN CheckIndexSize (size, _srcIndx, 5000)             'make sure we have enough mem
  369.     FN CheckIndexSize (2 * statCount, _remIndx, 50)
  370.     
  371.     LONG IF SYSERROR = _noErr                            'no memory error
  372.       FOR count = statCount - 1 TO 0 STEP -1
  373.         INDEX$ I (lineNum, _srcIndx) = gStmnts$(count)   'insert new source line
  374.         LONG IF count <> 0                               'skip all but original line
  375.           INDEX$ I (lineNum + 1, _remIndx) = ""          'to keep remarks lined up
  376.         END IF
  377.         INC(gTotalLines)                                 'make sure we keep total lines right
  378.       NEXT
  379.     END IF
  380.   END IF
  381. END FN
  382.  
  383.  
  384.  
  385.  
  386.  
  387. ' ------------------------------------------------------------------------
  388. ' this routine strips quoted strings from a designated string. it looks for
  389. ' a quote then begins replacing each subsequent char with a space until
  390. ' an ending quote is found.
  391. '
  392. ' source$      = the string to strip quoted strings from
  393. '
  394. LOCAL FN quoteBlaster$ (source$)
  395.   counter = 1
  396.   skip    = _false
  397.   strPtr& = @source$                                     'get pointer to our string
  398.   size%   = PEEK(strPtr&)                                'get string size
  399.   WHILE counter <= size%
  400.     char = PEEK(strPtr& + counter)                       'get next char in string
  401.     LONG IF char = _quote
  402.       DEF TOGGLE (skip)                                  'toggle our flag
  403.       POKE strPtr& + counter, _space                     'space over quoted areas
  404.     END IF
  405.     IF skip = _zTrue THEN POKE strPtr& + counter, _space'space over all chars
  406.     INC(counter)
  407.   WEND
  408. END FN = source$
  409.  
  410.  
  411.  
  412.  
  413.  
  414. ' ------------------------------------------------------------------------
  415. ' this routine strips spaces from the end of a designated string
  416. '
  417. ' source$        = the string to strip spaces from
  418.  
  419. LOCAL FN stripTrailingSpaces$ (source$)
  420.   DEF TRUNCATE (source$)
  421. END FN = source$
  422.  
  423.  
  424.  
  425.  
  426.  
  427. ' ------------------------------------------------------------------------
  428. ' this routine gets the chars in the designated string from the starting
  429. ' position until a space, comma, colon, or open parenthesis is located.
  430. '
  431. ' charPos        = position to begin char stripping
  432. ' source$        = the string to strip chars from
  433. ' endPosPtr&     = pointer to endPos var in calling routine
  434. '
  435. LOCAL FN getChars$ (@charPosPtr&, source$, @endPosPtr&)
  436.   temp$    = ""
  437.   strPtr&  = @source$
  438.   strSize  = PEEK (strPtr&)
  439.   charPos  = {charPosPtr&}
  440.   WHILE PEEK(strPtr& + charPos) = _space
  441.     INC (charPos)
  442.   WEND
  443.   startPos = charPos
  444.   DO
  445.     INC (charPos)
  446.     char = PEEK(strPtr& + charPos)
  447.   UNTIL char = _space OR char = _colon OR char = _comma OR char = _openP
  448.   POKE WORD charPosPtr&, startPos
  449.   POKE WORD endPosPtr&, charPos
  450. END FN = MID$(source$, startPos, charPos - startPos)
  451.  
  452.  
  453.  
  454.  
  455.  
  456.  
  457.  
  458. LOCAL FN parseOnBranches$ (source$, srcTmp$, keywd$, @strPtr&, @lCountPtr&)
  459.   TRON p
  460.   labelCount = {lCountPtr&}
  461.   LONG IF PEEK(strPtr&) > LEN (keywd$)
  462.     MID$ (source$, 1, 3) = "   "
  463.     tpos = INSTR(1, source$, keywd$)
  464.     tpos = INSTR(tpos, source$, " ") + 1                 'parse from comma. GOSUB parse will get first label
  465.     WHILE tpos    
  466.       'TRON x
  467.       temp$ = FN getChars$ (tpos, source$, endPos)
  468.       DEF TRUNCATE (temp$)
  469.       
  470.       matchFound = _false
  471.       FOR g = 0 TO labelCount
  472.         LONG IF UCASE$(gLabel$(g)) = UCASE$(temp$)
  473.           matchFound = _true
  474.           temp$      = gLabel$(g)                        'might have different case
  475.           g          = labelCount                        'end loop search
  476.         END IF
  477.       NEXT
  478.       
  479.       LONG IF matchFound = _false
  480.         gLabel$(labelCount) = temp$
  481.         INC(labelCount)
  482.       END IF
  483.       
  484.       search$ = temp$
  485.       temp$ = FN quoteMe$ (temp$)
  486.       FN replaceSomething (srcTmp$, tpos, search$, temp$)
  487.       FN replaceSomething (source$, tpos, search$, temp$)
  488.       
  489.       BLOCKMOVE @source$, strPtr&, LEN(source$) + 1
  490.       tpos = INSTR(tpos, source$, ",")
  491.       IF tpos <> 0 THEN INC(tpos)
  492.     WEND
  493.     
  494.     % lCountPtr&, labelCount                             'poke count back into var
  495.   END IF
  496. END FN = srcTmp$
  497.  
  498.  
  499.  
  500. LOCAL FN parseRegBranch$ (source$, srcTmp$, keywd$, @strPtr&, @lCountPtr&, goPos)
  501.   
  502.   labelCount = {lCountPtr&}
  503.   tpos = 1                                               'set initial position
  504.   sLen = INSTR (goPos + LEN (keywd$), source$, " ") + 1
  505.   temp$ = FN getChars$ (sLen, source$, endPos)
  506.   DEF TRUNCATE (temp$)
  507.   matchFound = _false
  508.   
  509.   FOR g = 0 TO labelCount - 1
  510.     LONG IF UCASE$(gLabel$(g)) = UCASE$(temp$)           'is there a match?
  511.       matchFound = _true                                 'set flag true
  512.       temp$      = gLabel$(g)                            'might have different case
  513.       g          = labelCount                            'end loop search
  514.     END IF
  515.   NEXT
  516.   
  517.   LONG IF matchFound = _false
  518.     gLabel$(labelCount) = temp$
  519.     INC(labelCount)
  520.   END IF
  521.   
  522.   
  523.   search$ = temp$
  524.   temp$ = FN quoteMe$ (temp$)
  525.   FN replaceSomething (srcTmp$, sLen, search$, temp$)
  526.   FN replaceSomething (source$, sLen, search$, temp$)
  527.   
  528.   BLOCKMOVE @source$, strPtr&, LEN(source$) + 1
  529.   % lCountPtr&, labelCount                               'poke count back into var
  530. END FN = srcTmp$
  531.  
  532.  
  533.  
  534.  
  535. SEGMENT
  536.  
  537.  
  538.  
  539.  
  540. ' -----------------------------------------------------------------
  541. ' source$       = source line to work upon
  542. ' maxLabels     = number of labels to search for
  543.  
  544. LOCAL FN checkForLabel$ (source$, maxLabels)
  545.   compare$ = UCASE$ (source$)
  546.   FOR labelCount = 0 TO maxLabels                        'look for all labels on line
  547.     thisLabel$  = UCASE$(gLabel$(labelCount))
  548.     quoteLabel$ = FN quoteMe$ (gLabel$(labelCount))
  549.     
  550.     '---- this section updates the THEN and ELSE label GOTO's on a line
  551.     tpos = INSTR(1, compare$, thisLabel$)
  552.     LONG IF tpos - 5 > 0
  553.       WHILE INSTR(tpos-5, compare$, "THEN") = tpos-5 OR INSTR(tpos-5, compare$, "ELSE") = tpos-5
  554.         lab$ = "GOTO " + quoteLabel$                     'inserts GOTO into line
  555.         
  556.         x$   = LEFT$(compare$, tpos -1)
  557.         LONG IF tpos + 1 < LEN(compare$)
  558.           x2$ = MID$(compare$, tpos + LEN(gLabel$(labelCount)), 255) + " "
  559.         XELSE
  560.           x2$ = ""
  561.         END IF
  562.         
  563.         y$   = LEFT$(source$, tpos -1)
  564.         LONG IF tpos + 1 < LEN(source$)
  565.           y2$ = MID$(source$, tpos + LEN(thisLabel$), 255)+" "
  566.         XELSE
  567.           y2$ = ""
  568.         END IF
  569.         
  570.         source$  = y$ + lab$ + y2$
  571.         compare$ = x$ + lab$ + x2$
  572.         
  573.         tpos = INSTR(tpos + 1, source$, thisLabel$)
  574.         'TRON x
  575.       WEND
  576.     END IF
  577.     
  578.     '---- Updates label on the line
  579.     tpos = INSTR(1, compare$, thisLabel$)
  580.     LONG IF VAL(gLabel$(labelCount))                     'if line num add a colon after it
  581.       addColon$ = ":"
  582.     XELSE                                                'otherwise make sure there is a colon after it!
  583.       addColon$ = ""
  584.       char = PEEK(@compare$ + LEN(gLabel$(labelCount)) + 1)
  585.     END IF
  586.     
  587.     LONG IF tpos <> 0                                    'updates line with the quoted label
  588.       LONG IF tpos = 1
  589.         FN replaceSomething (source$, tpos, thisLabel$, quoteLabel$)
  590.       XELSE
  591.         minusOne = PEEK (@source$ + tpos - 1)
  592.         plusOne = PEEK (@source$ + LEN (thisLabel$) + 1)
  593.         LONG IF minusOne = _space AND plusOne = _space
  594.           FN replaceSomething (source$, tpos, thisLabel$, quoteLabel$)
  595.         END IF
  596.       END IF
  597.       
  598.       LONG IF char = _colon
  599.         charPos  = INSTR (LEN(quoteLabel$), source$, ":")
  600.         LONG IF charPos = LEN(quoteLabel$) + 1
  601.           tmp$ = ":" : tmp2$ = ""
  602.           FN replaceSomething (source$, charPos, tmp$, tmp2$)
  603.         END IF
  604.       END IF
  605.       labelCount = maxLabels + 1                         'end search
  606.     END IF
  607.   NEXT labelCount
  608. END FN = source$
  609.  
  610.  
  611.  
  612.  
  613.  
  614. LOCAL
  615. DIM startPos, endPos
  616. LOCAL FN parseLabels
  617.   labelCount = 0                                         'label count
  618.   subCount = 0                                           'sub count
  619.   CLS
  620.   FOR lnCount = 0 TO gTotalLines
  621.     LONG IF lnCount MOD 10 = 0
  622.       PRINT%(10,20) "Creating label tables…"
  623.       PRINT%(10,40) "Currently on line#";lnCount
  624.       PRINT%(10,60) "Label count =";labelCount
  625.       PRINT%(10,80) "SUB count =";subCount
  626.     END IF
  627.     
  628.     source$    = INDEX$(lnCount, _srcIndx)
  629.     
  630.     LONG IF source$ <> ""                                'skip all blank lines
  631.       srcTmp$  = source$
  632.       source$ = FN quoteBlaster$(srcTmp$)                'strip quoted stuff from string
  633.       
  634.       '•• Parse --- SUB labels
  635.       tpos = INSTR(1,source$,"SUB ")
  636.       LONG IF tpos = 1                                   'only first position counts
  637.         tpos = tpos+3
  638.         temp$ = FN getChars$ (tpos, source$, endPos)
  639.         matchFound = _false
  640.         FOR g = 0 TO subCount
  641.           LONG IF UCASE$(gSubs$(g)) = UCASE$(temp$)
  642.             matchFound = _true
  643.             temp$      = gSubs$(g)                       'might have different case
  644.             g          = subCount                        'end loop search
  645.           END IF
  646.         NEXT
  647.         LONG IF matchFound = _false
  648.           gSubs$(subCount) = temp$
  649.           INC(subCount)
  650.         END IF
  651.         
  652.       END IF
  653.       
  654.       '•• Parse --- ON GOSUB ---
  655.       goPos = INSTR(1, source$, "GOSUB")                 'ON GOSUB labels line
  656.       LONG IF goPos <> 0
  657.         onPos = INSTR(1, source$, "ON ")                 'ON GOSUB labels line
  658.         LONG IF onPos = 1
  659.           srcTmp$ = FN parseOnBranches$ (source$, srcTmp$, "GOSUB", source$, labelCount)
  660.         XELSE
  661.           srcTmp$ = FN parseRegBranch$ (source$, srcTmp$, "GOSUB", source$, labelCount, goPos)
  662.         END IF
  663.       END IF
  664.       
  665.       goPos = INSTR(1, source$, "GOTO")                  'ON GOSUB labels line
  666.       LONG IF goPos <> 0
  667.         onPos = INSTR(1, source$, "ON ")                 'ON GOSUB labels line
  668.         LONG IF onPos = 1
  669.           srcTmp$ = FN parseOnBranches$ (source$, srcTmp$, "GOTO", source$, labelCount)
  670.         XELSE
  671.           srcTmp$ = FN parseRegBranch$ (source$, srcTmp$, "GOTO", source$, labelCount, goPos)
  672.         END IF
  673.       END IF
  674.       
  675.       INDEX$(lnCount, _srcIndx) = srcTmp$                'put the revised line back
  676.     END IF
  677.   NEXT lnCount
  678.   
  679.   COMPILE LONG IF _debug
  680.     TROFF
  681.   COMPILE END IF
  682.   
  683.   'use list to replace all labels with dbl-quoted UCASE labels
  684.   ' 
  685.   CLS
  686.   FOR y = 1 TO gTotalLines                               'look through all the lines
  687.     
  688.     LONG IF y MOD 10 = 0
  689.       PRINT%(10,20) "Updating actual labels…"
  690.       PRINT%(10,40) "Currently updating line#";y
  691.     END IF
  692.     
  693.     source$    = INDEX$(y, _srcIndx)
  694.     FN stripLeadChar(source$, _space, 1)
  695.     srcTmp$     = source$                                'get line without remark in it
  696.     source$    = FN quoteBlaster$(srcTmp$)               'strip quoted stuff from string
  697.     source$    = UCASE$(source$)                         'labels are case insensitive
  698.     
  699.     LONG IF sCount
  700.       FOR z = 0 TO sCount - 1
  701.         
  702.         '---- Update the SUB name to be FN subname
  703.         temp$ = UCASE$(gSubs$(z))
  704.         
  705.         tpos = INSTR(1, source$, temp$)
  706.         WHILE tpos AND (INSTR(1, source$,"SUB") > 1 OR INSTR(1, source$,"SUB") = 0)
  707.           cpos = INSTR(1,source$, "CALL")
  708.           LONG IF cpos = tpos - 5                        'is there a CALL in front of subname?
  709.             LONG IF cpos > 1                             'strip the CALL out of the line
  710.               x$  = LEFT$(source$,cpos-1)
  711.               y$  = LEFT$(srcTmp$,cpos-1)
  712.             XELSE
  713.               x$ = "": y$ =""
  714.             END IF                       
  715.             x2$ = RIGHT$(source$, LEN(source$) - (cpos + 3))
  716.             y2$ = RIGHT$(srcTmp$,  LEN(srcTmp$)  - (cpos + 3))
  717.             
  718.             source$ = x$ + x2$
  719.             srcTmp$  = y$ + y2$
  720.             
  721.             tpos = INSTR(1,source$,temp$)                'get new position
  722.           END IF
  723.           
  724.           
  725.           '•• insert FN in front of SUB call
  726.           LONG IF PEEK(@source$+tpos+LEN(temp$)) <> _openP AND PEEK(@source$+tpos+LEN(temp$)+1) <> _openP 
  727.             paren1$ = "("
  728.             elsePos = INSTR(1,source$,"ELSE")
  729.             FOR tt = tpos TO LEN(source$)
  730.               LONG IF PEEK(@source$+tt) = _colon OR tt = LEN(source$) OR tt = elsePos
  731.                 
  732.                 bu = 1                                   'calculate how much to backup
  733.                 WHILE PEEK(@source$+tt-bu) = _space 
  734.                   INC(bu)
  735.                   'TRON x
  736.                 WEND
  737.                 
  738.                 x$   = LEFT$(srcTmp$, tt - bu)
  739.                 LONG IF tt +1 < LEN(srcTmp$)
  740.                   x2$ = MID$(srcTmp$, tt, 255)+" "
  741.                 XELSE
  742.                   x2$ = ""
  743.                 END IF
  744.                 
  745.                 y$   = LEFT$(source$, tt - bu)
  746.                 LONG IF tt +1 < LEN(source$)
  747.                   y2$ = MID$(source$, tt, 255)+" "
  748.                 XELSE
  749.                   y2$ = ""
  750.                 END IF
  751.                 source$ = y$ + ") " + y2$    
  752.                 srcTmp$  = x$ + ") " + x2$  
  753.                 
  754.                 tt = LEN(source$)
  755.               END IF
  756.             NEXT
  757.             
  758.           XELSE
  759.             paren1$ = ""
  760.           END IF
  761.           
  762.           lab$ = "FN " + gSubs$(z) +" " + paren1$                  :'inserts FN in front of sub call
  763.           
  764.           x$   = LEFT$(srcTmp$, tpos -1)
  765.           LONG IF tpos +1 < LEN(srcTmp$)
  766.             x2$ = MID$(srcTmp$, tpos+LEN(gSubs$(z))+1, 255)+" "
  767.           XELSE
  768.             x2$ = ""
  769.           END IF
  770.           
  771.           y$   = LEFT$(source$, tpos -1)
  772.           LONG IF tpos +1 < LEN(source$)
  773.             y2$ = MID$(source$, tpos+LEN(gSubs$(z))+1, 255)+" "
  774.           XELSE
  775.             y2$ = ""
  776.           END IF
  777.           
  778.           source$ = y$ + SPACE$(LEN(lab$)) + y2$   :     'don't insert sub name into source$
  779.           srcTmp$  = x$ + lab$ + x2$                :    'only srcTmp$
  780.           
  781.           tpos = INSTR(1, source$, temp$)
  782.           'TRON x
  783.         WEND
  784.       NEXT
  785.     END IF
  786.     
  787.     LONG IF srcTmp$ <> ""
  788.       srcTmp$ = FN checkForLabel$ (srcTmp$, labelCount)
  789.     END IF
  790.     
  791.     WHILE VAL(srcTmp$)                                   'strip line numbers now
  792.       srcTmp$ = RIGHT$(srcTmp$, LEN(srcTmp$)-1)
  793.     WEND
  794.     
  795.     INDEX$(y, _srcIndx) = srcTmp$                        'put the revised line back
  796.   NEXT
  797.   
  798. END FN
  799.  
  800.  
  801.  
  802.  
  803.  
  804.  
  805.  
  806.  
  807. ' ------------------------------------------------------------------------
  808. ' this routine converts IF THEN/ELSE statements to LONG IF/XELSE
  809. '
  810. ' srcCount       = element in source code INDEX$
  811. '
  812. LOCAL FN parseXelse$ (srcCount)                          'fix IF-THEN-ELSE to LONG IF - XELSE
  813.   source$ = INDEX$ (srcCount, _srcIndx)                  'get source line
  814.   LONG IF source$ <> ""                                  'if it isn’t empty
  815.     INDEX$ (srcCount, _srcIndx) = source$                'get source line
  816.   END IF
  817. END FN
  818.  
  819.  
  820.  
  821.  
  822.  
  823. ' ------------------------------------------------------------------------
  824. '
  825. LOCAL FN parseIfThens (srcCount)
  826.   source$ = INDEX$ (srcCount, _srcIndx)
  827.   
  828.   LONG IF source$ <> ""
  829.     ifPos   = INSTR (1, source$, "IF")
  830.     
  831.     LONG IF ifPos > 0
  832.       elsePos = INSTR (1, source$, "ELSEIF")
  833.       endPos  = INSTR (1, source$, "END IF")
  834.       thenPos = INSTR (ifPos, source$, "THEN")
  835.       
  836.       LONG IF (ifPos < thenPos) AND (thenPos = PEEK(@source$) - 3)
  837.         LONG IF (ifPos - 4) = elsePos
  838.           INC (gTotalIFs)
  839.           search$ = "ELSEIF" : replace$ = "XELSE IF"
  840.           FN replaceSomething (source$, elsePos, search$, replace$)
  841.           ifPos = INSTR (1, source$, "IF")
  842.           LONG IF ifPos <> 0
  843.             INDEX$ I(srcCount + 1, _srcIndx) = MID$ (source$, ifPos, LEN (source$))
  844.             INDEX$ I(srcCount + 1, _remIndx) = ""
  845.             source$ = LEFT$ (source$, ifPos - 1)
  846.             INC (gTotalLines)
  847.           END IF
  848.         END IF
  849.         
  850.         
  851.         LONG IF ifPos = 1
  852.           search$ = "IF" : replace$ = "LONG IF"
  853.           FN replaceSomething (source$, ifPos, search$, replace$)
  854.         END IF
  855.         
  856.         
  857.         thenPos = INSTR (ifPos, source$, "THEN")
  858.         LONG IF thenPos <> 0
  859.           search$ = "THEN" : replace$ = ""
  860.           FN replaceSomething (source$, thenPos, search$, replace$)
  861.         END IF
  862.       XELSE
  863.         LONG IF (ifPos - 4) = endPos
  864.           LONG IF gTotalIFs > 0
  865.             FOR count = 1 TO gTotalIFs
  866.               INDEX$ I(srcCount + 1, _srcIndx) = "END IF"
  867.               INDEX$ I(srcCount + 1, _remIndx) = ""
  868.               INC (gTotalLines)
  869.             NEXT count
  870.             gTotalIFs = 0
  871.           END IF
  872.         END IF
  873.       END IF
  874.       
  875.       DEF TRUNCATE (source$)
  876.       INDEX$ (srcCount, _srcIndx) = source$
  877.     END IF
  878.   END IF
  879. END FN
  880.  
  881.  
  882.  
  883.  
  884.  
  885.  
  886.  
  887. LOCAL
  888. DIM quotePairs (40,1)                                    'dbl-quate pairs
  889. LOCAL FN parseLineColons (lineNum)
  890.   count = 0
  891.   DO
  892.     gStmnts$(count) = ""
  893.     INC (count)
  894.   UNTIL gStmnts$(count) = ""
  895.   
  896.   source$    = INDEX$(lineNum, _srcIndx)
  897.   srcTmp$    = source$
  898.   source$    = FN quoteBlaster$(srcTmp$)                 'strip quoted stuff from string
  899.   
  900.   DEF TRUNCATE (source$)
  901.   statCount = 0                                          'Ok, now parse out the statements into gStmnts$(n)
  902.   LONG IF remarkPos <> 1                                 'if remark is first pos then skip parse
  903.     found = INSTR(1, source$, ":")
  904.     LONG IF found = 0
  905.       gStmnts$(0) = srcTmp$
  906.       remarks$ = ""
  907.       INC(statCount)
  908.     XELSE
  909.       WHILE found                                        'ok, let's look for colons
  910.         gStmnts$(statCount) = LEFT$(srcTmp$, found -1)   'get statement
  911.         srcTmp$  = RIGHT$(srcTmp$,  LEN(srcTmp$)-found)  'peel off unparsed section
  912.         source$ = RIGHT$(source$, LEN(source$)-found)    'peel off unparsed section
  913.         INC(statCount)
  914.         found = INSTR(1, source$, ":")
  915.         'TRON x
  916.         LONG IF found = 0
  917.           gStmnts$(statCount) = srcTmp$
  918.           INC(statCount)
  919.         END IF
  920.       WEND
  921.     END IF
  922.   END IF
  923.   
  924.   FN stripLeadChar (gStmnts$(statCount), _space, 1)      'strip leading spaces
  925.   FN insertFix(lineNum,statCount)
  926.   
  927. END FN = statCount
  928.  
  929.  
  930.  
  931.  
  932.  
  933.  
  934. ' ------------------------------------------------------------------------
  935. ' this routine parses any IF statements into multiple lines and converts
  936. ' single line multiple statements (separated by colons) in multiple line
  937. ' single statement lines.
  938. '
  939. LOCAL FN fixLineRefs
  940.   CLS
  941.   FOR lnCount = 0 TO gTotalLines
  942.     LONG IF lnCount MOD 10 = 0
  943.       PRINT%(10,20) "Parsing IF statements…"
  944.       PRINT%(10,40) "Currently on line#";lnCount
  945.     END IF
  946.     FN parseIfThens (lnCount)
  947.   NEXT
  948.   
  949.   CLS
  950.   FOR lnCount = 0 TO gTotalLines
  951.     'TRON x
  952.     LONG IF lnCount MOD 10 = 0
  953.       PRINT%(10,20) "Parsing multi-line statements…"
  954.       PRINT%(10,40) "Currently on line#";lnCount
  955.     END IF
  956.     linesAdded = FN parseLineColons(lnCount)
  957.   NEXT
  958. END FN
  959.  
  960.  
  961.  
  962.  
  963.  
  964. ' ------------------------------------------------------------------------
  965. ' this routine saves the entire converted file to disk
  966. '
  967. LOCAL FN saveIt
  968.   ppos = INSTR(1, gFilename$, ".")
  969.   LONG IF ppos > 1
  970.     gFilename$ = LEFT$(gFilename$, ppos-1)
  971.   END IF
  972.   
  973.   saveAs$ = gFilename$ + ".CONV"
  974.   filename$ = FILES$ (_fSave, "Save converted file as:", saveAs$, volRefNum%)
  975.   LONG IF LEN(filename$)
  976.     CURSOR _watchCursor
  977.     CLS: TEXT _monaco, 9
  978.     PRINT%(10,20) "Saving converted source file to disk…"
  979.     
  980.     DEF OPEN "TEXT"
  981.     OPEN "O",1 , filename$, , volRefNum%
  982.     LONG IF SYSERROR = _noErr
  983.       PRINT #1, source$
  984.       FOR lineCnt = 0 TO gHeaderLines                    'output our header info
  985.         source$ = INDEX$(lineCnt, _hedIndx)
  986.         PRINT #1, source$
  987.       NEXT
  988.       FOR lineCnt = 0 TO gTotalLines                     'output the revised source text
  989.         remark$ = INDEX$(lineCnt, _remIndx)
  990.         LONG IF remark$ <> ""
  991.           IF LEFT$(remark$, 1) <> "'" THEN remark$ = "'" + remark$
  992.         END IF
  993.         source$ = INDEX$(lineCnt, _srcIndx) + remark$    'add remarks back into source
  994.         PRINT #1, source$                                'save to file
  995.       NEXT
  996.       CLOSE #1
  997.     XELSE
  998.       item = FN doAlrt ("Unable to save converted file.")
  999.     END IF
  1000.   END IF
  1001.   CALL INITCURSOR
  1002. END FN
  1003.  
  1004.  
  1005.  
  1006.  
  1007.  
  1008.  
  1009. LOCAL FN parseSUB$ (srcCount)
  1010.   source$ = INDEX$ (srcCount, _srcIndx)
  1011.   spos = INSTR (1, source$, "END SUB")
  1012.   LONG IF spos
  1013.     source$ = "END FN"
  1014.     INC (gExitSub)
  1015.   XELSE
  1016.     spos = INSTR (1, source$, "SUB ")
  1017.     LONG IF spos = 1
  1018.       source$ = RIGHT$ (source$, LEN(source$) - 4)
  1019.       spos = INSTR (1, source$, "STATIC")
  1020.       LONG IF spos
  1021.         source$ = LEFT$ (source$, spos - 1)
  1022.         source$ = "LONG FN " + source$
  1023.       XELSE
  1024.         source$ = "LOCAL FN " + source$
  1025.       END IF
  1026.     END IF
  1027.   END IF
  1028.   INDEX$ (srcCount, _srcIndx) = source$
  1029. END FN
  1030.  
  1031.  
  1032.  
  1033. SEGMENT
  1034.  
  1035.  
  1036. ' ------------------------------------------------------------------------
  1037. ' this routine reads in the QB->FB data file that describes the differences
  1038. ' between the two products syntax
  1039. '
  1040. LOCAL FN ReadDataFile
  1041.   CLS
  1042.   PRINT%(10,20) "Now loading conversion file into memory…"
  1043.   CURSOR _watchCursor
  1044.   
  1045.   OPEN "I",1,"QB->FB.data",,SYSTEM (_aplVol)             'must be in same folder...
  1046.   LONG IF SYSERROR = _noErr
  1047.     keyCount = -1                                        'init our var
  1048.     DO
  1049.       INC(keyCount)                                      'increment keyword var
  1050.       LINE INPUT #1, gConv$(0,keyCount)                  'get old syntax
  1051.       LINE INPUT #1, gConv$(1,keyCount)                  'get new syntax
  1052.       
  1053.       FN stripLeadChar (gConv$(0,keyCount), _space, 1)   'strip any front spaces
  1054.       FN stripLeadChar (gConv$(1,keyCount), _space, 1)
  1055.       
  1056.     UNTIL EOF(1) OR gConv$(0,keyCount) = ""              'eof or empty keyword ends file input
  1057.     DEC(keyCount)                                        'increment keyword var
  1058.     CLOSE #1
  1059.   XELSE
  1060.     item = FN doAlrt("Unable to open “QB->FB.data” file.")
  1061.     END
  1062.   END IF
  1063.   CALL INITCURSOR                                        'close keyword file
  1064. END FN = keyCount
  1065.  
  1066.  
  1067.  
  1068.  
  1069.  
  1070. ' ------------------------------------------------------------------------
  1071. ' this routine extracts the keyword from the conversion data file
  1072. '
  1073. ' keyCount      = keyword element to extract from gConv$()
  1074. ' keyword$      = actual keyword to search for
  1075. '
  1076. LOCAL FN GetKeyWord$ (keyCount)
  1077.   charPos = 0
  1078.   qbSyntax$ = gConv$ (0, keyCount)
  1079.   strPtr&   = @qbSyntax$
  1080.   DO                                                     'skip all chars not alphabetical in nature
  1081.     INC (charPos)
  1082.     char = PEEK(strPtr& + charPos)
  1083.   UNTIL (char => _"A" AND char <= _"Z") OR (char => _"a" AND char <= _"z")
  1084.   startPos = charPos
  1085.   DO                                                     'now cycle thru keyword until finished
  1086.     INC (charPos)
  1087.     char = PEEK(strPtr& + charPos)
  1088.     IF char = _"_" THEN POKE strPtr& + charPos, _space
  1089.   UNTIL char = _space OR char = _openP OR charPos > PEEK(strPtr&)
  1090.   keyword$ = MID$ (qbSyntax$, startPos, charPos - startPos)'get keyword from line
  1091. END FN = keyword$
  1092.  
  1093.  
  1094.  
  1095.  
  1096.  
  1097.  
  1098. ' ------------------------------------------------------------------------
  1099. ' this routine does all the work of converting the original QB keywords to
  1100. '
  1101. LOCAL FN CountChar (@synPtr&, charType)
  1102.   charCount = 0
  1103.   charPos = 1
  1104.   strLen = PEEK (synPtr&)
  1105.   DO
  1106.     char = PEEK (synPtr& + charPos)
  1107.     LONG IF char = charType
  1108.       INC (charCount)
  1109.     END IF
  1110.     INC (charPos)
  1111.   UNTIL charPos > strLen
  1112. END FN = charCount
  1113.  
  1114.  
  1115.  
  1116.  
  1117.  
  1118.  
  1119.  
  1120. ' -----------------------------------------------------------------
  1121. '
  1122. LOCAL FN SkipParens (srcPtr&, charPos)
  1123.   parenCount = 1
  1124.   DO
  1125.     INC (charPos)
  1126.     char = PEEK (srcPtr& + charPos)                      'get next char in source
  1127.     SELECT char
  1128.       CASE _openP  : INC (parenCount)
  1129.       CASE _closeP : DEC (parenCount)
  1130.     END SELECT
  1131.   UNTIL char = _closeP AND parenCount = 0
  1132. END FN = charPos
  1133.  
  1134.  
  1135.  
  1136.  
  1137.  
  1138.  
  1139. ' -----------------------------------------------------------------
  1140. ' this routine extracts all characters between the starting and ending
  1141. ' points of the specified string. the start point is defined by charPos, 
  1142. ' the ending point by a comma or when the search exceeeds the search
  1143. ' strings length. the result is placed into the parameter pointed to by 
  1144. ' paramPtr.
  1145. '
  1146. ' srcPtr&      = pointer to source string
  1147. ' charPos      = starting position of search
  1148. '
  1149. LOCAL FN ExtractParams (srcPtr&, charPos)
  1150.   FN StartFN (4)
  1151.   srcLen = PEEK (srcPtr&)                                'setup initial variables
  1152.   startPos = charPos
  1153.   paramCount = 1                                         'parameter element count
  1154.   endExtract = _false                                    'loop until finished
  1155.   :
  1156.   DO
  1157.     char = PEEK (srcPtr& + charPos)                      'get next char in source
  1158.     SELECT                                               'now act upon it
  1159.       CASE char = _comma OR charPos > srcLen OR char = _closeP'is it a comma or end of source
  1160.         paramLen = charPos - startPos                    'get length to strip
  1161.         paramPtr& = @gParam$(paramCount)                 'get pointer to storage
  1162.         POKE paramPtr&, paramLen                         'put length into storage string
  1163.         BLOCKMOVE srcPtr& + startPos, paramPtr& + 1, paramLen'no pass parameter
  1164.         :                                                'do some cleaning up of parameters
  1165.         FN stripLeadChar (gParam$(paramCount), _space, 1)'strip any leading spaces
  1166.         LONG IF INSTR (1, gParam$(paramCount), "(") = 1  'does it start with a parenthesis?
  1167.           FN stripLeadChar (gParam$(paramCount), _openP, 1)'strip any leading spaces
  1168.           tmp$ = ")" : tmp2$ = ""
  1169.           FN replaceSomething (gParam$(paramCount), PEEK(paramPtr&), tmp$, tmp2$)
  1170.         END IF
  1171.         :
  1172.         INC (paramCount)
  1173.         startPos = charPos + 1                           'skip past last comma
  1174.       CASE char = _openP 
  1175.         charPos = FN SkipParens (srcPtr&, charPos) 
  1176.     END SELECT
  1177.     IF startPos <= srcLen THEN INC (charPos) ELSE endExtract = _true
  1178.   UNTIL endExtract = _true
  1179.   FN StopFN (4)
  1180.   :
  1181. END FN = charPos
  1182.  
  1183.  
  1184.  
  1185.  
  1186.  
  1187.  
  1188.  
  1189.  
  1190.  
  1191.  
  1192.  
  1193.  
  1194. ' ------------------------------------------------------------------------
  1195. ' use this routine to locate a specific char within a string. somewhat analogous
  1196. ' to INSTR but works with a string pointer instead of the string itself
  1197. '
  1198. LOCAL FN FindChar (srcPtr&, charPos, char)
  1199.   strLen = PEEK (srcPtr&)
  1200.   WHILE PEEK (srcPtr& + charPos) <> char AND charPos <= strLen
  1201.     INC (charPos)
  1202.   WEND
  1203.   IF PEEK (srcPtr& + charPos) <> char THEN charPos = 0
  1204. END FN = charPos
  1205.  
  1206.  
  1207.  
  1208.  
  1209.  
  1210.  
  1211.  
  1212. ' ------------------------------------------------------------------------
  1213. ' this routine does all the work of converting the original QB keywords to
  1214. ' FB format
  1215. '
  1216. LOCAL FN GetAndFillParams (srcPtr&, keyPtr&, keyCount, charPos)
  1217.   
  1218.   FN StartFN (3)
  1219.   
  1220.   FOR count = 0 TO 9
  1221.     gParam$(count) = ""
  1222.     gStmnt$(count) = ""
  1223.   NEXT count
  1224.   
  1225.   keyType    = ASC(gConv$(_qb, keyCount))
  1226.   gParam$(0) = CHR$ (keyType)
  1227.   
  1228.   SELECT keyType
  1229.     CASE _caret
  1230.     CASE _att
  1231.       charPos = FN FindChar (srcPtr&, charPos, _space)
  1232.       IF charPos <> 0 THEN FN ExtractParams (srcPtr&, charPos)
  1233.       
  1234.     CASE _pound
  1235.       charPos = FN FindChar (srcPtr&, charPos, _openP) + 1
  1236.       FN ExtractParams (srcPtr&, charPos)
  1237.       
  1238.     CASE _asterisk
  1239.       origPos = charPos
  1240.       charPos = FN FindChar (srcPtr&, charPos, _space)
  1241.       LONG IF charPos = 0
  1242.         charPos = FN FindChar (srcPtr&, origPos, _openP)
  1243.       END IF
  1244.       FN ExtractParams (srcPtr&, charPos + 1)
  1245.       
  1246.     CASE ELSE
  1247.       tmp$ = "Conversion type “" + syntax$ + "” in line#" + STR$(keyCount)
  1248.       item = FN doAlrt (tmp$)
  1249.       IF item = 2 THEN END
  1250.   END SELECT
  1251.   
  1252.   charPos = INSTR (1, gConv$ (_qb, keyCount), "_")       'strip underscores from keyword
  1253.   tmp$ = "_" : tmp2$ = " "
  1254.   IF charPos THEN FN replaceSomething (syntax$, charPos, tmp$, tmp2$)
  1255.   FN StopFN (3)
  1256. END FN
  1257.  
  1258.  
  1259.  
  1260.  
  1261.  
  1262.  
  1263. ' ------------------------------------------------------------------------
  1264. ' this routine takes the parameter variables extracted from the original
  1265. ' source line and places them into the correct fb syntax sequence.
  1266. '
  1267. ' srcPtr&      = pointer to original source string
  1268. ' keyPtr&      = pointer to keyword
  1269. ' keyCount     = element count in gConv$()
  1270. '
  1271. LOCAL FN ConvertSyntax (srcPtr&, keyPtr&, keyCount)
  1272.   FN StartFN (8)
  1273.   DIM source$
  1274.   DIM keyword$
  1275.   :
  1276.   BLOCKMOVE srcPtr&, @source$, PEEK (srcPtr&) + 1        'get us some strings to work with
  1277.   BLOCKMOVE keyPtr&, @keyword$, PEEK(keyPtr&) + 1
  1278.   ucSource$ = UCASE$(source$)
  1279.   :
  1280.   paramCount = 9                                         'start at the top
  1281.   WHILE gParam$ (paramCount) = ""                        'is this element empty?
  1282.     DEC (paramCount)                                     'then reduce by one
  1283.   WEND                                                   'until an element is filled
  1284.   :
  1285.   startPos = INSTR (1, ucSource$, keyword$)              'get starting position of keyword
  1286.   LONG IF paramCount = 0                                 'no parameters so set to end of keyword
  1287.     endPos   = startPos + PEEK(@keyword$)
  1288.   XELSE                                                  'got a parameter
  1289.     endPos   = INSTR (startPos, ucSource$, UCASE$(gParam$ (paramCount))) + LEN (gParam$ (paramCount))
  1290.   END IF
  1291.   LONG IF endPos = PEEK(@source$)                        'make sure we get that last 
  1292.     INC(endPos)                                          'parenthesis in a source code line
  1293.   END IF
  1294.   :
  1295.   SELECT gParam$(0)                                      'any special handling required?
  1296.     CASE "*" :                                           'check for presence of CALL
  1297.       charPos = INSTR (1, ucSource$, "CALL ")            'is CALL there?
  1298.       LONG IF charPos <> 0 AND charPos < startPos        'make sure its before the keyword
  1299.         startPos = startPos - 5                          'then adjust start position
  1300.       END IF
  1301.     CASE ELSE
  1302.   END SELECT
  1303.   :
  1304.   'TRON p
  1305.   LONG IF endPos > startPos
  1306.     oldkey$  = MID$ (source$, startPos, endPos - startPos)'and ending pos
  1307.     :                                                    'get the entire keyword with variables
  1308.     tmp2$ = gConv$ (_fb, keyCount)
  1309.     FN replaceSomething (source$, startPos, oldkey$, tmp2$)
  1310.     :                                                    'and replace it with new line
  1311.     charPos = 1
  1312.     paramCount = 1
  1313.     WHILE paramCount < 10
  1314.       oldkey$ = STR$(paramCount)                         'make param a match string 
  1315.       tmp$ = " " : tmp2$ = "~"
  1316.       FN replaceSomething (oldkey$, 1, tmp$, tmp2$)      'insert tilde char to match string
  1317.       charPos = INSTR(charPos, source$, oldkey$)         'get its position in source
  1318.       tmp2$ = gParam$ (paramCount)
  1319.       IF charPos <> 0 THEN FN replaceSomething (source$, charPos, oldkey$, tmp2$)
  1320.       charPos = 1
  1321.       INC (paramCount)
  1322.     WEND
  1323.     :
  1324.     BLOCKMOVE @source$, srcPtr&, PEEK(@source$) + 1      'replace original with modified
  1325.   XELSE
  1326.     tmp$ = "Error in parameter#" + STR$(paramCount) + "//" + source$
  1327.     item = FN doAlrt (tmp$)
  1328.     IF item = 1 THEN END
  1329.   END IF
  1330.   FN StopFN (8)
  1331. END FN
  1332.  
  1333.  
  1334.  
  1335.  
  1336.  
  1337.  
  1338.  
  1339.  
  1340. ' ------------------------------------------------------------------------
  1341. ' this routine does all the work of converting the original QB keywords to
  1342. ' FB format
  1343. '
  1344. ' charPos       = char position where match was found
  1345. ' srcPtr&       = pointer to original source$
  1346. ' keyPtr&       = pointer to keyword$
  1347. ' keyCount      = element position of key in gConv$()
  1348. '
  1349. LOCAL
  1350. DIM source$
  1351. LOCAL FN UpdateSyntax (charPos, @srcPtr&, @keyPtr&, keyCount)
  1352.   
  1353.   charPos = charPos + PEEK(keyPtr&)                      'skip start char past keyword
  1354.   FN GetAndFillParams (srcPtr&, keyPtr&, keyCount, charPos)'fill params for keyword
  1355.   
  1356.   FN StartFN (2)
  1357.   SELECT ASC(gParam$(0))                                 'now execute different conversion types
  1358.     CASE _caret                                          'insert helpful msg
  1359.       tmp$ = "" : tmp2$ = gConv$ (_fb, keyCount)
  1360.       FN replaceSomething (=srcPtr&, 1, tmp$, tmp2$)
  1361.       
  1362.       
  1363.     CASE _att                                            'convert non-parenthesis keywords
  1364.       'FN StripParams (srcPtr&, charPos)
  1365.       FN ConvertSyntax (srcPtr&, keyPtr&, keyCount)
  1366.       
  1367.       
  1368.     CASE _pound                                          'convert non-parenthesis keywords
  1369.       charPos = FN FindChar (srcPtr&, 1, _openP)         'is there a parenthesis
  1370.       'FN StripParams (srcPtr&, charPos)                            'strip parenthesis params
  1371.       FN ConvertSyntax (srcPtr&, keyPtr&, keyCount)
  1372.       
  1373.       
  1374.     CASE _asterisk                                       'convert toolbox calls
  1375.       FN ConvertSyntax (srcPtr&, keyPtr&, keyCount)
  1376.       BLOCKMOVE srcPtr&, @source$, PEEK(srcPtr&) + 1     'get source itself (sigh!)
  1377.       DO
  1378.         charPos = INSTR (charPos, source$, "VARPTR")     'is a VARPTR present?
  1379.         LONG IF charPos <> 0                             'if so, fix it to work
  1380.           tmp$ = "" : tmp2$ = "#"
  1381.           FN replaceSomething (source$, charPos, tmp$, tmp2$)'add # to use value of address
  1382.           charPos = charPos + 6                          'make sure to skip last VARPTR
  1383.         END IF
  1384.       UNTIL charPos = 0
  1385.       BLOCKMOVE @source$, srcPtr&, PEEK(@source$) + 1    'get source itself (sigh!)
  1386.       
  1387.     CASE ELSE
  1388.       item = FN doAlrt ("Incorrect conversion type in data file.")
  1389.       END
  1390.   END SELECT
  1391.   FN StopFN (2)
  1392. END FN
  1393.  
  1394.  
  1395.  
  1396.  
  1397.  
  1398.  
  1399. ' ------------------------------------------------------------------------
  1400. ' this routine see's if a keyword is really there
  1401. '
  1402. LOCAL FN CheckKeyword (@srcPtr&, charPos, @keyPtr&)
  1403.   beforFlag = _false
  1404.   afterFlag = _false
  1405.   srcLen = PEEK (srcPtr&)
  1406.   keyLen = PEEK (keyPtr&)
  1407.   LONG IF charPos <> 1
  1408.     beforChar = PEEK(srcPtr& + charPos - 1)              'keyword
  1409.     LONG IF beforChar = _space OR beforChar = _colon OR beforChar = _comma
  1410.       beforFlag = _true
  1411.     END IF
  1412.   XELSE
  1413.     beforFlag = _true
  1414.   END IF
  1415.   afterChar = PEEK(srcPtr& + charPos + keyLen)
  1416.   LONG IF afterChar = _space OR afterChar = _colon OR afterChar = _openP OR afterChar = _pound
  1417.     afterFlag = _true
  1418.   END IF
  1419. END FN = (afterFlag AND beforFlag)
  1420.  
  1421.  
  1422.  
  1423.  
  1424.  
  1425.  
  1426. ' ------------------------------------------------------------------------
  1427. ' this routine does all the work of converting the original QB keywords to
  1428. ' FB format
  1429. '
  1430. LOCAL FN convertLines
  1431.   DIM 255 source$
  1432.   
  1433.   maxKeyCount = FN ReadDataFile
  1434.   LONG IF maxKeyCount > 0
  1435.     FN StartFN (1)
  1436.     CLS
  1437.     CURSOR _watchCursor
  1438.     FOR srcCount = 0 TO gTotalLines
  1439.       'TRON x
  1440.       :
  1441.       FN parseSUB$ (srcCount)
  1442.       'FN parseXelse$ (srcCount)
  1443.       :
  1444.       source$ = INDEX$ (srcCount, _srcIndx)
  1445.       
  1446.       PRINT%(10,20) "Converting keyword syntax from QB to FB format…"
  1447.       PRINT%(10,40) "Now converting line#";srcCount
  1448.       
  1449.       LONG IF source$ <> ""                              'do we have something to convert?
  1450.         DEF TRUNCATE (source$)                           'strip all spaces at end
  1451.         FN stripLeadChar (source$, _space, 1)            'and the beginning
  1452.         ucSource$ = UCASE$(source$)
  1453.         keyCount = 0
  1454.         DO
  1455.           keyword$ = FN GetKeyWord$ (keyCount)           'get keyword to search for
  1456.           keyLen   = PEEK(@keyword$)
  1457.           srcLen   = PEEK(@source$)
  1458.           :
  1459.           LONG IF keyword$ <> "" AND (keyLen <= srcLen)
  1460.             charPos = INSTR (1, ucSource$, keyword$)
  1461.             LONG IF charPos <> 0 AND keyCount <= maxKeyCount'is it in this source line?
  1462.               :                                          'if so, replace old syntax with new
  1463.               keyFlag = FN CheckKeyword (source$, charPos, keyword$)
  1464.               LONG IF keyFlag
  1465.                 FN UpdateSyntax (charPos, source$, keyword$, keyCount)
  1466.                 keyCount = maxKeyCount
  1467.               END IF
  1468.               :
  1469.             END IF
  1470.           END IF 
  1471.           INC (keyCount)                                 'add 1 to get next keyword
  1472.         UNTIL keyCount > maxKeyCount OR keyCount > _maxKeywords'cycle thru all keywords
  1473.         INDEX$ (srcCount, _srcIndx) = source$            'replace original source line
  1474.       END IF                                             'source$ is not empty
  1475.     NEXT srcCount
  1476.   XELSE
  1477.     BEEP : PRINT "Error count =";maxKeyCount
  1478.   END IF
  1479.   FN StopFN (1)
  1480.   CALL INITCURSOR
  1481. END FN
  1482.  
  1483.  
  1484.  
  1485.  
  1486.  
  1487.  
  1488. LOCAL
  1489. DIM srcTmp$(300)
  1490. LOCAL FN formatProgram
  1491.   INDEX$(0,_hedIndx)  = "'QB program converted to FutureBASIC syntax"
  1492.   INDEX$(1,_hedIndx)  = "'Program name was: " + gFilename$
  1493.   INDEX$(2,_hedIndx)  = ""
  1494.   INDEX$(3,_hedIndx)  = "'-------------------- Header ---------------------------"
  1495.   INDEX$(4,_hedIndx)  = "'Put a RESOURCES statement here if needed"
  1496.   INDEX$(5,_hedIndx)  = ""
  1497.   INDEX$(6,_hedIndx)  = "COMPILE 0, _caseInsensitive _strResources _macsbugLabels "
  1498.   INDEX$(7,_hedIndx)  = ""
  1499.   INDEX$(8,_hedIndx)  = "'-------------------- Globals --------------------------"
  1500.   INDEX$(9,_hedIndx)  = ""
  1501.   INDEX$(10,_hedIndx)  = "'Place DIM or GLOBALS statements here as required"
  1502.   INDEX$(11,_hedIndx)  = "END GLOBALS"
  1503.   INDEX$(12,_hedIndx)  = ""
  1504.   INDEX$(13,_hedIndx) = "'-------------------- Functions ------------------------"
  1505.   gHeaderLines = 13
  1506.   
  1507.   FOR x = 0 TO gTotalLines
  1508.     
  1509.     source$ = INDEX$(x, _srcIndx)                        'move SUBs to function section of program
  1510.     LONG IF INSTR(1,source$,"LONG FN") OR INSTR(1,source$,"LOCAL FN")
  1511.       counter = 0
  1512.       curPos  = x
  1513.       DO
  1514.         srcTmp$(counter) = source$
  1515.         INC(counter)
  1516.         INC(curPos)
  1517.         source$= INDEX$(curPos, _srcIndx)
  1518.       UNTIL INSTR(1,source$,"END FN")
  1519.       srcTmp$(counter) = source$
  1520.       
  1521.       FOR z = 0 TO counter
  1522.         INDEX$(gHeaderLines, _hedIndx) = srcTmp$(z)
  1523.         INC(gHeaderLines)
  1524.       NEXT
  1525.       INC(gHeaderLines)
  1526.       
  1527.       FOR z = 0 TO counter
  1528.         INDEX$ D (x, _srcIndx)
  1529.         DEC(gTotalLines)
  1530.       NEXT
  1531.     END IF
  1532.     
  1533.     source$ = INDEX$(x, _srcIndx)                        'global variables?
  1534.     LONG IF INSTR(1,source$,"DIM SHARED ")               'global variables?
  1535.       source$ = RIGHT$(source$, LEN(source$)-11)
  1536.       source$ = "DIM "+ source$
  1537.       INDEX$ I(8, _srcIndx) = source$                    'insert the global vars into global area
  1538.       INC(gHeaderLines)
  1539.       INDEX$ D (x, _srcIndx)
  1540.       DEC(gTotalLines)
  1541.     END IF
  1542.     
  1543.     
  1544.     source$ = INDEX$(x,_srcIndx)                         'check for resource file being opened...
  1545.     srcTmp$  = source$
  1546.     source$ = UCASE$(source$)
  1547.     LONG IF INSTR(1,source$,"OPENRESFILE ")              'resources file?
  1548.       tpos = INSTR(1,srcTmp$,CHR$(_quote))               'double quotes?
  1549.       fname$ = ""
  1550.       LONG IF tpos
  1551.         DO
  1552.           fname$ = fname$ + CHR$(PEEK(@srcTmp$+tpos))
  1553.           tpos = tpos +1
  1554.         UNTIL PEEK(@srcTmp$+tpos) =  34
  1555.         fname$ = fname$ + CHR$(_quote)
  1556.         source$ = "RESOURCES "+fname$
  1557.         INDEX$ (4, _srcIndx) = source$                   'insert the global vars into global area
  1558.         INDEX$(x, _srcIndx) = "see RESOURCES at top of program -->"+srcTmp$
  1559.       END IF
  1560.     END IF
  1561.     
  1562.   NEXT
  1563. END FN
  1564.  
  1565.  
  1566.  
  1567. '----------------------- Main --------------------------
  1568.  
  1569. COMPILE LONG IF _debug
  1570.   TROFF
  1571. COMPILE END IF
  1572. FLUSHEVENTS
  1573. FN initialize
  1574. FN OpenFile
  1575. LONG IF gFilename$ <> ""
  1576.   start& = FN TICKCOUNT
  1577.   CURSOR _watchCursor
  1578.   :
  1579.   FN parseLabels
  1580.   FN fixLineRefs
  1581.   FN convertLines
  1582.   FN formatProgram
  1583.   FN saveIt
  1584.   :
  1585.   CALL INITCURSOR
  1586. END IF
  1587. '
  1588. CLS
  1589. SOUND "Stopped"
  1590. TEXT _monaco, 9, _boldBit%, 0 : COLOR _zRed
  1591. PRINT%(10,20) "Conversion is done!"
  1592. TEXT _monaco, 9, 0, 0 : COLOR _zBlack
  1593. totalTime! = ((FN TICKCOUNT - start&)/60)/60
  1594. PRINT%(10,40) "Total Conversion Time: ";USING "###.###";totalTime!; " minutes"
  1595. PRINT%(10,60) "Press mouse button to quit."
  1596. '
  1597. DO
  1598. UNTIL FN BUTTON
  1599. END
  1600.